package main

import (
	"bufio"
	"encoding/json"
	"flag"
	"fmt"
	"gitee.com/daka1004/devops-runner/cmd"
	"gitee.com/daka1004/devops-runner/common/logs"
	"gitee.com/daka1004/devops-runner/modules/setting"
	"github.com/kardianos/service"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"text/template"
)

//// 配置结构
//var setting = struct {
//	ServerIP   string `json:"server_ip"`
//	ServerPort int    `json:"server_port"`
//	Token      string `json:"token"`
//	ConfigPath string `json:"-"` // 不导出到配置文件
//}{
//	ServerIP:   "",
//	ServerPort: 34567, // 默认端口
//	Token:      "",
//}

// 定义服务结构体
type agentService struct{}

// 服务启动逻辑
func (s *agentService) Start(svc service.Service) error {
	// 这里可以添加启动服务的逻辑，例如启动你的应用逻辑
	log.Println("服务已启动")
	go runMainLogic() // 在后台运行主逻辑
	return nil
}

// 服务停止逻辑
func (s *agentService) Stop(svc service.Service) error {
	// 这里可以添加停止服务的逻辑，例如关闭你的应用逻辑
	log.Println("服务已停止")
	return nil
}

// 运行主逻辑
func runMainLogic() {
	getwd, err2 := os.Getwd()
	if err2 != nil {

	}
	err := logs.Init(filepath.Join(getwd, "logs", "devopsRunner.log"), false, false)
	if err != nil {

	}
	// 输出启动信息
	logs.Infof("启动 DevOps Agent: 服务器=%s:%d, Token=%s",
		setting.Setting.ServerIP,
		setting.Setting.ServerPort,
		maskToken(setting.Setting.Token))

	// 这里添加原始的主命令逻辑
	// 由于原始代码中没有定义cmd，这里用一个占位函数代替
	logs.Info("执行主逻辑...")
	cmd.Run()
}

// 掩码 Token
func maskToken(token string) string {
	if len(token) <= 8 {
		return token
	}
	return token[:4] + "..." + token[len(token)-4:]
}

var (
	mu         sync.Mutex            // 互斥锁
	configPath = ".agent.properties" // 优先加载的配置文件路径
)

// 加载配置文件
func loadConfig(path string) error {
	data, err := ioutil.ReadFile(path)
	if err != nil {
		return err
	}
	return json.Unmarshal(data, &setting.Setting)
}
func loadConfigbak() error {
	// 1. 检查 .agent.properties 是否存在
	if _, err := os.Stat(configPath); err == nil {
		if err := loadPropertiesConfig(configPath); err == nil {
			return nil // 加载成功，直接返回
		}
		// 若加载失败，继续尝试默认配置
	}

	// 2. 加载默认配置文件（如 config.json 或 config.toml）
	defaultConfigPath := "devops_agent_config.json" // 替换为实际默认配置路径
	if _, err := os.Stat(defaultConfigPath); err == nil {
		return loadDefaultConfig(defaultConfigPath)
	}
	// 3. 若均不存在，返回错误（或使用空配置）
	return fmt.Errorf("配置文件 %s 或 %s 不存在", configPath, defaultConfigPath)
}

// 配置结构体
type Config struct {
	ServerIP string `toml:"serverip"` // 必选参数
	Token    string `toml:"token"`    // 必选参数
	Port     int    `toml:"port"`     // 可选参数，默认 34567
}

// 加载 .agent.properties（INI 格式）
func loadPropertiesConfig(path string) error {
	file, err := os.Open(path)
	if err != nil {
		return err
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())
		if line == "" || strings.HasPrefix(line, "#") { // 忽略空行和注释
			continue
		}
		keyValue := strings.SplitN(line, "=", 2)
		if len(keyValue) != 2 {
			continue
		}
		key := strings.TrimSpace(keyValue[0])
		value := strings.TrimSpace(keyValue[1])
		switch key {
		case "serverip":
			setting.Setting.ServerIP = value
		case "token":
			setting.Setting.Token = value
		case "port":
			setting.Setting.ServerPort, _ = strconv.Atoi(value) // 可选参数，转换失败时保留默认值
		}
	}
	return scanner.Err()
}

// 加载默认配置文件（如 JSON）
func loadDefaultConfig(path string) error {
	data, err := os.ReadFile(path)
	if err != nil {
		return err
	}
	return json.Unmarshal(data, setting.Setting)
}

// 保存配置文件
func saveConfig(path string) {
	configToSave := struct {
		ServerIP   string `json:"server_ip"`
		ServerPort int    `json:"server_port"`
		Token      string `json:"token"`
	}{
		ServerIP:   setting.Setting.ServerIP,
		ServerPort: setting.Setting.ServerPort,
		Token:      setting.Setting.Token,
	}

	data, err := json.MarshalIndent(configToSave, "", "  ")
	if err != nil {
		log.Fatalf("序列化配置失败: %v", err)
	}

	if err := ioutil.WriteFile(path, data, 0644); err != nil {
		log.Fatalf("写入配置文件失败: %v", err)
	}

	log.Printf("配置已保存到: %s", path)
}

// 生成单个脚本
func generateScript(filename, tmpl string) {
	file, err := os.Create(filename)
	if err != nil {
		log.Fatalf("创建脚本文件失败: %v", err)
	}
	defer file.Close()

	t := template.Must(template.New("script").Parse(tmpl))
	if err := t.Execute(file, setting.Setting); err != nil {
		log.Fatalf("生成脚本失败: %v", err)
	}

	// 为 Linux/macOS 脚本添加可执行权限
	if filepath.Ext(filename) == ".sh" {
		os.Chmod(filename, 0755)
	}

	fmt.Printf("已生成: %s\n", filename)
}

func main() {
	configPath := flag.String("config", "devops_agent_config.json", "配置文件路径")
	serverIP := flag.String("serverip", "", "服务器 IP 地址")
	serverport := flag.Int("serverport", 0, "端口号")
	token := flag.String("token", "", "认证令牌")
	generateConfig := flag.Bool("generate-config", false, "生成配置文件模板")
	installSvc := flag.Bool("install-service", false, "安装为 Windows 服务")
	uninstallSvc := flag.Bool("uninstall-service", false, "卸载 Windows 服务")
	runAsSvc := flag.Bool("service", false, "作为 Windows 服务运行")
	flag.Parse()

	setting.Setting.ConfigPath = *configPath

	// 处理生成配置文件的请求
	if *generateConfig {
		saveConfig(*configPath)
		fmt.Printf("配置文件模板已生成: %s\n", *configPath)
		return
	}

	// 检查是否使用原始启动方式（直接传递serverip和token作为参数）
	cmdLineArgsProvided := false
	if len(os.Args) >= 7 && os.Args[5] == "-serverport" {

		atoi, _ := strconv.Atoi(os.Args[6])
		setting.Setting.ServerPort = atoi
	}
	if len(os.Args) >= 5 &&
		os.Args[1] == "-serverip" &&
		os.Args[3] == "-token" {
		// 原始启动方式: ./devops-runner -serverip serverip -token token
		setting.Setting.ServerIP = os.Args[2]
		setting.Setting.Token = os.Args[4]
		cmdLineArgsProvided = true
	} else {
		// 新的启动方式: 使用配置文件或命令行标志
		// 从配置文件加载设置
		configExists := false
		if _, err := os.Stat(*configPath); err == nil {
			if err := loadConfig(*configPath); err != nil {
				//if err := loadConfig(); err != nil {
				log.Fatalf("加载配置文件失败: %v", err)
			}
			configExists = true
		}

		// 从命令行参数覆盖设置
		if *serverIP != "" {
			setting.Setting.ServerIP = *serverIP
			cmdLineArgsProvided = true
		}
		if *token != "" {
			setting.Setting.Token = *token
			cmdLineArgsProvided = true
		}
		if *serverport != 0 {
			setting.Setting.ServerPort = (*serverport)
			cmdLineArgsProvided = true
		}

		// 如果通过命令行提供了参数且配置文件不存在，则保存配置
		if cmdLineArgsProvided && !configExists {
			saveConfig(*configPath)
		}
	}

	// 如果通过命令行提供了参数，无论配置文件是否存在都保存配置
	if cmdLineArgsProvided {
		saveConfig(*configPath)
	}

	// 验证必要参数
	if setting.Setting.ServerIP == "" {
		log.Fatal("必须提供服务器 IP 地址 (-serverip 或作为命令行参数)")
	}
	if setting.Setting.Token == "" {
		log.Fatal("必须提供认证令牌 (-token 或作为命令行参数)")
	}

	// 生成启动/停止脚本
	osType := runtime.GOOS
	if !*runAsSvc {
		if osType == "windows" {
			generateScript("start_devops_agent.bat", windowsStartTemplate)
			generateScript("stop_devops_agent.bat", windowsStopTemplate)
			generateScript("install_service.bat", windowsServiceTemplate)
		} else if osType == "linux" || osType == "darwin" {
			generateScript("start_devops_agent.sh", linuxStartTemplate)
			generateScript("stop_devops_agent.sh", linuxStopTemplate)
		}
	}

	// 处理 Windows 服务相关操作
	if osType == "windows" {
		svcConfig := &service.Config{
			Name:        "DevOpsAgentService",
			DisplayName: "DevOps Agent Service",
			Description: "DevOps Agent Service for Server Communication",
		}

		s, err := service.New(&agentService{}, svcConfig)
		if err != nil {
			log.Fatalf("创建服务失败: %v", err)
		}

		if *installSvc {
			err = s.Install()
			if err != nil {
				log.Fatalf("安装服务失败: %v", err)
			}
			fmt.Println("服务安装成功")
			err = s.Start()
			if err != nil {
				log.Fatalf("启动服务失败: %v", err)
			}
			fmt.Println("服务已启动")
		} else if *uninstallSvc {
			err = s.Stop()
			if err != nil {
				log.Fatalf("停止服务失败: %v", err)
			}
			err = s.Uninstall()
			if err != nil {
				log.Fatalf("卸载服务失败: %v", err)
			}
			fmt.Println("服务卸载成功")
		} else if *runAsSvc {
			err = s.Run()
			if err != nil {
				log.Fatalf("运行服务失败: %v", err)
			}
		} else {
			// 非服务模式，直接运行主逻辑
			runMainLogic()
		}
	} else {
		// 非 Windows 系统，直接运行主逻辑
		runMainLogic()
	}
}

// 脚本模板
const windowsStartTemplate = `@echo off
SET SERVER_IP={{.ServerIP}}
SET SERVER_PORT={{.ServerPort}}
SET AGENT_TOKEN={{.Token}}
SET CONFIG_PATH={{.ConfigPath}}

echo Starting DevOps Agent...
start /B cmd /C "devops-runner.exe -config %CONFIG_PATH% > devops_agent.log 2>&1"
echo DevOps Agent started. Check devops_agent.log for details.
`

const windowsStopTemplate = `@echo off
taskkill /F /IM devops-runner.exe
echo DevOps Agent stopped.
`

const windowsServiceTemplate = `@echo off
SET SERVICE_NAME=DevOpsAgentService
SET BINARY_PATH=%~dp0devops-runner.exe
SET CONFIG_PATH=%~dp0{{.ConfigPath}}

echo Installing DevOps Agent as Windows Service...
sc create %SERVICE_NAME% binPath= "%BINARY_PATH% -config %CONFIG_PATH%" start= auto displayname= "DevOps Agent Service"
sc description %SERVICE_NAME% "DevOps Agent Service for Server Communication"

echo Starting DevOps Agent Service...
net start %SERVICE_NAME%
`

const linuxStartTemplate = `#!/bin/bash
SERVER_IP="{{.ServerIP}}"
SERVER_PORT="{{.ServerPort}}"
TOKEN="{{.Token}}"
CONFIG_PATH="{{.ConfigPath}}"

echo "Starting DevOps Agent..."
nohup ./devops-runner -config "$CONFIG_PATH" > devops_agent.log 2>&1 &
echo "DevOps Agent started. Check devops_agent.log for details."
`

const linuxStopTemplate = `#!/bin/bash
pkill -f devops-runner
echo "DevOps Agent stopped."
`

/*
// 服务启动逻辑
func (s *agentService) Start(svc service.Service) error {
	// 这里可以添加启动服务的逻辑，例如启动你的应用逻辑
	log.Println("服务已启动")
	go runMainLogic() // 在后台运行主逻辑
	return nil
}

// 服务停止逻辑
func (s *agentService) Stop(svc service.Service) error {
	// 这里可以添加停止服务的逻辑，例如关闭你的应用逻辑
	log.Println("服务已停止")
	return nil
}

// 运行主逻辑
func runMainLogic() {
	// 输出启动信息
	log.Printf("启动 DevOps Agent: 服务器=%s:%d, Token=%s",
		setting.Setting.ServerIP,
		setting.Setting.ServerPort,
		maskToken(setting.Setting.Token))

	// 这里添加原始的主命令逻辑
	// 例如: cmd.Run()
	// 由于原始代码中没有定义cmd，这里用一个占位函数代替
	log.Println("执行主逻辑...")
	cmd.Run()
}

// 掩码 Token
func maskToken(token string) string {
	if len(token) <= 8 {
		return token
	}
	return token[:4] + "..." + token[len(token)-4:]
}

// 加载配置文件
func loadConfig(path string) error {
	data, err := ioutil.ReadFile(path)
	if err != nil {
		return err
	}
	return json.Unmarshal(data, &setting.Setting)
}

// 保存配置文件
func saveConfig(path string) {
	configToSave := struct {
		ServerIP   string `json:"server_ip"`
		ServerPort int    `json:"server_port"`
		Token      string `json:"token"`
	}{
		ServerIP:   setting.Setting.ServerIP,
		ServerPort: setting.Setting.ServerPort,
		Token:      setting.Setting.Token,
	}

	data, err := json.MarshalIndent(configToSave, "", "  ")
	if err != nil {
		log.Fatalf("序列化配置失败: %v", err)
	}

	if err := ioutil.WriteFile(path, data, 0644); err != nil {
		log.Fatalf("写入配置文件失败: %v", err)
	}
}

// 生成单个脚本
func generateScript(filename, tmpl string) {
	file, err := os.Create(filename)
	if err != nil {
		log.Fatalf("创建脚本文件失败: %v", err)
	}
	defer file.Close()

	t := template.Must(template.New("script").Parse(tmpl))
	if err := t.Execute(file, setting.Setting); err != nil {
		log.Fatalf("生成脚本失败: %v", err)
	}

	// 为 Linux/macOS 脚本添加可执行权限
	if filepath.Ext(filename) == ".sh" {
		os.Chmod(filename, 0755)
	}

	fmt.Printf("已生成: %s\n", filename)
}

func main() {
	configPath := flag.String("config", "devops_agent_config.json", "配置文件路径")
	serverIP := flag.String("serverip", "", "服务器 IP 地址")
	token := flag.String("token", "", "认证令牌")
	generateConfig := flag.Bool("generate-config", false, "生成配置文件模板")
	installSvc := flag.Bool("install-service", false, "安装为 Windows 服务")
	uninstallSvc := flag.Bool("uninstall-service", false, "卸载 Windows 服务")
	runAsSvc := flag.Bool("service", false, "作为 Windows 服务运行")
	flag.Parse()

	setting.Setting.ConfigPath = *configPath

	// 处理生成配置文件的请求
	if *generateConfig {
		saveConfig(*configPath)
		fmt.Printf("配置文件模板已生成: %s\n", *configPath)
		return
	}

	// 检查是否使用原始启动方式（直接传递serverip和token作为参数）
	if len(os.Args) >= 5 &&
		os.Args[1] == "-serverip" &&
		os.Args[3] == "-token" {
		// 原始启动方式: ./devops-runner -serverip serverip -token token
		setting.Setting.ServerIP = os.Args[2]
		setting.Setting.Token = os.Args[4]
	} else {
		// 新的启动方式: 使用配置文件或命令行标志
		// 从配置文件加载设置
		configExists := false
		if _, err := os.Stat(*configPath); err == nil {
			if err := loadConfig(*configPath); err != nil {
				log.Fatalf("加载配置文件失败: %v", err)
			}
			configExists = true
		}

		// 从命令行参数覆盖设置
		cmdLineArgsProvided := false
		if *serverIP != "" {
			setting.Setting.ServerIP = *serverIP
			cmdLineArgsProvided = true
		}
		if *token != "" {
			setting.Setting.Token = *token
			cmdLineArgsProvided = true
		}

		// 如果通过命令行提供了参数且配置文件不存在，则保存配置
		if cmdLineArgsProvided && !configExists {
			saveConfig(*configPath)
		}
	}

	// 验证必要参数
	if setting.Setting.ServerIP == "" {
		log.Fatal("必须提供服务器 IP 地址 (-serverip 或作为命令行参数)")
	}
	if setting.Setting.Token == "" {
		log.Fatal("必须提供认证令牌 (-token 或作为命令行参数)")
	}

	// 生成启动/停止脚本
	osType := runtime.GOOS
	if !*runAsSvc {
		if osType == "windows" {
			generateScript("start_devops_agent.bat", windowsStartTemplate)
			generateScript("stop_devops_agent.bat", windowsStopTemplate)
			generateScript("install_service.bat", windowsServiceTemplate)
		} else if osType == "linux" || osType == "darwin" {
			generateScript("start_devops_agent.sh", linuxStartTemplate)
			generateScript("stop_devops_agent.sh", linuxStopTemplate)
		}
	}

	// 处理 Windows 服务相关操作
	if osType == "windows" {
		svcConfig := &service.Config{
			Name:        "DevOpsAgentService",
			DisplayName: "DevOps Agent Service",
			Description: "DevOps Agent Service for Server Communication",
		}

		s, err := service.New(&agentService{}, svcConfig)
		if err != nil {
			log.Fatalf("创建服务失败: %v", err)
		}

		if *installSvc {
			err = s.Install()
			if err != nil {
				log.Fatalf("安装服务失败: %v", err)
			}
			fmt.Println("服务安装成功")
			err = s.Start()
			if err != nil {
				log.Fatalf("启动服务失败: %v", err)
			}
			fmt.Println("服务已启动")
		} else if *uninstallSvc {
			err = s.Stop()
			if err != nil {
				log.Fatalf("停止服务失败: %v", err)
			}
			err = s.Uninstall()
			if err != nil {
				log.Fatalf("卸载服务失败: %v", err)
			}
			fmt.Println("服务卸载成功")
		} else if *runAsSvc {
			err = s.Run()
			if err != nil {
				log.Fatalf("运行服务失败: %v", err)
			}
		} else {
			// 非服务模式，直接运行主逻辑
			runMainLogic()
		}
	} else {
		// 非 Windows 系统，直接运行主逻辑
		runMainLogic()
	}
}

// 脚本模板
const windowsStartTemplate = `@echo off
SET SERVER_IP={{.ServerIP}}
SET SERVER_PORT={{.ServerPort}}
SET AGENT_TOKEN={{.Token}}
SET CONFIG_PATH={{.ConfigPath}}

echo Starting DevOps Agent...
start /B cmd /C "devops-runner.exe -config %CONFIG_PATH% > devops_agent.log 2>&1"
echo DevOps Agent started. Check devops_agent.log for details.
`

const windowsStopTemplate = `@echo off
taskkill /F /IM devops-runner.exe
echo DevOps Agent stopped.
`

const windowsServiceTemplate = `@echo off
SET SERVICE_NAME=DevOpsAgentService
SET BINARY_PATH=%~dp0devops-runner.exe
SET CONFIG_PATH=%~dp0{{.ConfigPath}}

echo Installing DevOps Agent as Windows Service...
sc create %SERVICE_NAME% binPath= "%BINARY_PATH% -config %CONFIG_PATH%" start= auto displayname= "DevOps Agent Service"
sc description %SERVICE_NAME% "DevOps Agent Service for Server Communication"

echo Starting DevOps Agent Service...
net start %SERVICE_NAME%
`

const linuxStartTemplate = `#!/bin/bash
SERVER_IP="{{.ServerIP}}"
SERVER_PORT="{{.ServerPort}}"
TOKEN="{{.Token}}"
CONFIG_PATH="{{.ConfigPath}}"

echo "Starting DevOps Agent..."
nohup ./devops-runner -config "$CONFIG_PATH" > devops_agent.log 2>&1 &
echo "DevOps Agent started. Check devops_agent.log for details."
`

const linuxStopTemplate = `#!/bin/bash
pkill -f devops-runner
echo "DevOps Agent stopped."
`*/

//func main() {
//	if len(os.Args) < 2 {
//		log.Fatal("Usage: ops-runner <serverip>")
//	}
//	setting.ServerIP = os.Args[1]
//	setting.ServerPort = 34567
//
//	cmd.Run()
//}

// 假设 setting 包用于存储全局配置
//var setting = struct {
//	ServerIP   string
//	ServerPort int
//}{}
/*
func main() {
	// 解析命令行参数
	configPath := flag.String("config", "", "配置文件路径")
	serverIP := flag.String("serverip", "", "服务器 IP 地址")
	token := flag.String("token", "", "认证令牌")
	flag.Parse()

	// 从配置文件加载设置（如果提供了配置文件）
	if *configPath != "" {
		if err := loadConfig(*configPath); err != nil {
			log.Fatalf("加载配置文件失败: %v", err)
		}
	}

	// 从命令行参数覆盖设置（如果提供）
	if *serverIP != "" {
		setting.ServerIP = *serverIP
	}
	if *token != "" {
		setting.Token = *token
	}

	// 验证必要参数
	if setting.ServerIP == "" {
		log.Fatal("必须提供服务器 IP 地址 (-serverip 或在配置文件中设置)")
	}
	if setting.Token == "" {
		log.Fatal("必须提供认证令牌 (-token 或在配置文件中设置)")
	}

	// 设置默认端口（如果未设置）
	if setting.ServerPort == 0 {
		setting.ServerPort = 34567
	}

	// 输出启动信息
	log.Printf("启动 Agent: 服务器=%s:%d, Token=%s",
		setting.ServerIP,
		setting.ServerPort,
		maskToken(setting.Token))

	// 运行主命令
	cmd.Run()
}

// 加载配置文件
func loadConfig(path string) error {
	// 实现配置文件加载逻辑
	// 例如，使用 JSON 或 YAML 解析配置文件
	// 这里简化处理，假设使用 JSON
	file, err := os.Open(path)
	if err != nil {
		return err
	}
	defer file.Close()

	// 解析配置文件内容到 setting 结构体
	// 例如:
	// decoder := json.NewDecoder(file)
	// return decoder.Decode(&setting)

	return nil // 示例返回
}

// 掩码 Token，只显示前4位和后4位，保护敏感信息
func maskToken(token string) string {
	if len(token) <= 8 {
		return token
	}
	return token[:4] + "..." + token[len(token)-4:]
}
*/
